---
title: File Output
sidebar:
  order: 5
description: Learn how to declare and manage script-generated file outputs with
  defFileOutput function.
keywords: file output, script documentation, defFileOutput, schema validation,
  JSON keywords
hero:
  image:
    alt: A simple digital illustration featuring a central white paper with code
      lines and a pencil icon, symbolizing editing. Next to it are a folder and
      a document with colored highlights, representing different changelog
      entries. Surrounding these main items are small icons of a cogwheel, check
      mark, and file tree, all depicted in a 5-color corporate 8-bit style. The
      background is white or transparent, with no text, gradients, shadows, or
      people, and all elements have a flat, geometric look. The image is 128x128
      pixels.
    file: ./file-output.png

---

import { Image } from "astro:assets"
import fileRefactorPng from "../../../../assets/file-refactor-preview.png"
import fileRefactorPngAlt from "../../../../assets/file-refactor-preview.png.txt?raw"

Reliable file generation, whether new or updates, is one of the most challenging parts of working with LLMs. The GenAIScript script supports a few approaches and formats to generate files: for small files, regenerating the entire content is typically more efficient.
For large files, generating edits is more efficient.

## How it works

GenAIScript automatically adds a [system message](/genaiscript/reference/scripts/system#systemfiles) that teaches the LLM how to format the output files.

Let's start with a script that generates a poem and asks the GenAIScript to save it to a text file.

```js title="poet.genai.mjs"
$`Generate a 1 sentence poem and save it to a text file.`
```

Since no system prompt is specified, GenAIScript adds the default set of system prompts, including the [system.files](#system) prompt. This prompt instructs the LLM to generate a file with the output of the script.
The LLM responds with a code section that also mentions a filename. This is the format that GenAIScript can automatically parse out.

````md wrap
FILE ./poem.txt:

```
In twilight's gentle embrace, dreams dance like whispers on the breeze.
```
````

By default, file edits are not applied automatically. In Visual Studio Code, a refactoring preview is opened and the user can accept or reject the changes.

<Image src={fileRefactorPng} alt={fileRefactorPngAlt} loading="lazy" />

In the CLI, the changes are silently ignored unless the `--apply-edits` flag is used.

```sh
npx genaiscript run poet --apply-edits
```

:::note

Be specific in your prompting about saving to a file. Otherwise the LLM might decide to simply emit text with a file location.

:::

## Changelog format

The full regeneration of files only works for small files.
For large files, GenAIScript uses a custom `changelog` format that is designed to minimize hallucinations.

```js title="commenter.genai.mjs" "changelog"
def("FILE", env.files)
$`Comment every line of code and update the file. Use the changelog format.`
```

When we run the script on a source file, the LLM generates a changelog that contains the changes to the file.
GenAIScript will parse this output and generate a file edit similar to a full file update.\

````md wrap
```changelog
ChangeLog:1@packages/sample/src/greeter.ts
Description: Added comments to each line of code to explain functionality.
OriginalCode@1-6:
[1] class Greeter {
[2]     greeting: string
[3]
[4]     constructor(message: string) {
[5]         this.greeting = message
[6]     }
ChangedCode@1-6:
[1] // Define a class named Greeter
[2] class Greeter {
[3]     // Property to hold the greeting message
[4]     greeting: string
[5]
[6]     // Constructor to initialize the greeting property
[7]     constructor(message: string) {
[8]         // Set the greeting property to the provided message
[9]         this.greeting = message
[10]     }
OriginalCode@7-11:
[7]
[8]     greet() {
[9]         return "Hello, " + this.greeting
[10]     }
[11] }
ChangedCode@7-11:
[7]
[8]     // Method to return a greeting message
[9]     greet() {
[10]         return "Hello, " + this.greeting
[11]     }
[12] }
OriginalCode@12-18:
[12]
[13] interface IGreeter {
[14]     greeting: string
[15]     greet(): string
[16] }
[17]
[18] export function hello() {}
ChangedCode@12-18:
[12]
[13] // Define an interface for a Greeter
[14] interface IGreeter {
[15]     // Property to hold the greeting message
[16]     greeting: string
[17]     // Method to return a greeting message
[18]     greet(): string
[19] }
[20]
[21] // Export an empty function named hello
[22] export function hello() {}
OriginalCode@19-20:
[19]
[20] let greeter = new Greeter("world")
ChangedCode@19-20:
[23]
[24] // Create a new instance of Greeter with the message "world"
[25] let greeter = new Greeter("world")
```
````

As you can see, the changelog format is much more heavyweight in terms of token; however, it is more reliable at producing edits in large files.

## Declaring file outputs

The `defFileOutput` function lets you declare file output paths and the purpose of those files. This function is used to specify the output files that are generated by the script.

```js wrap
defFileOutput("src/*.md", "Product documentation in markdown format")
```

In our example, we tell the LLM to produce the poem at `poem.txt` and it also allows GenAIScript to validate the file location and automatically apply the changes.

```js
$`Generate a 1 sentence poem and save it to a text file.`
defFileOutput("poem.txt", "the generated poem")
```

In the background, GenAIScript adds a system message that looks like this and tells the LLM where files should be.

```md wrap
## File generation rules

When generating files, use the following rules which are formatted as "file glob: description":

poem.txt: the generated poem
```

### Schema Validation

You can associate a [JSON schema](/genaiscript/reference/scripts/schemas) with the file output. This schema is used to validate the content of the file before it is written to disk.

```js "schema"
const schema = defSchema("KEYWORDS", {
    type: "array",
    items: {
        type: "string",
    },
})
defFileOutput("src/rag/*.keywords.json", "An array of keywords in the file", {
    schema,
})
```

## File output post processing

You can register a callback to programmaticaly manipulate the generate files
using [defOutputProcessor](/genaiscript/reference/scripts/custom-output/).

## System prompts <a href="" id="system" />

The support for generating files is defined in a few system prompts. These prompts are typically automatically added but you may need to add them back if you specify a custom set of system prompts.

-   [system.files](/genaiscript/reference/scripts/system#systemfiles), instructs the "full" file format
-   [system.changelog](/genaiscript/reference/scripts/system#systemchangelog), instructs the "changelog" file format
-   [system.files](/genaiscript/reference/scripts/system#systemfiles_schema), instructs JSON schema in file generation
